package com.luxoft.scoremanager.server.service.impl;

import com.luxoft.scoremanager.server.dao.repository.ComponentDao;
import com.luxoft.scoremanager.server.dao.repository.ComponentValueDao;
import com.luxoft.scoremanager.server.dao.repository.ScorePackageDao;
import com.luxoft.scoremanager.server.dao.repository.StaticDataDao;
import com.luxoft.scoremanager.server.model.bean.ComponentBean;
import com.luxoft.scoremanager.server.model.bean.ScorePackageBean;
import com.luxoft.scoremanager.server.model.bean.StaticDataBean;
import com.luxoft.scoremanager.server.service.PackageManagerService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static com.google.common.base.Preconditions.checkArgument;


@Service
public class BasicPackageManagerService implements PackageManagerService {
    @Resource
    private ComponentDao componentDao;

    @Resource
    private ScorePackageDao scorePackageDao;

    @Resource
    private StaticDataDao staticDataDao;

    @Resource
    private ComponentValueDao componentValuesDao;

    public BasicPackageManagerService() {
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void addComponentToScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(id != null, "id should be provided");
        checkArgument(componentBean != null, "component should be provided");

        com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue = new com.luxoft.scoremanager.server.model.entity.ComponentValue(componentBean);
        //id is checked
        //noinspection ConstantConditions
        componentValue.setScorePackage(scorePackageDao.findOne(id));
        componentValuesDao.save(componentValue);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void deleteComponentFromScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(id != null, "id should be provided");
        checkArgument(componentBean != null, "component should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(componentBean.getId() != null, "component id should be provided");
        com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue = new com.luxoft.scoremanager.server.model.entity.ComponentValue(componentBean);
        //id is checked
        //noinspection ConstantConditions
        componentValue.setScorePackage(scorePackageDao.findOne(id));
        componentValuesDao.delete(componentValue);

    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateComponentListInScorePackageByPackageId(Integer id, List<ComponentBean> componentBeanList) {
        checkArgument(componentBeanList != null, "component should be provided");
        //argument is checked
        //noinspection ConstantConditions
        for (ComponentBean componentBean : componentBeanList) {
            checkArgument(componentBean != null, "component should be provided");
            //this is null checking method
            //noinspection ConstantConditions
            checkArgument(componentBean.getId() != null, "component id should be provided");
            com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue = new com.luxoft.scoremanager.server.model.entity.ComponentValue(componentBean);
            componentValue.setScorePackage(scorePackageDao.findOne(id));
            componentValuesDao.saveAndFlush(componentValue);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateComponentInScorePackageByPackageId(Integer id, ComponentBean componentBean) {
        checkArgument(componentBean != null, "component should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(componentBean.getId() != null, "component id should be provided");
        com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue = new com.luxoft.scoremanager.server.model.entity.ComponentValue(componentBean);
        componentValue.setScorePackage(scorePackageDao.findOne(id));
        componentValuesDao.saveAndFlush(componentValue);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public void updateScorePackage(ScorePackageBean scorePackageBean) {
        checkArgument(scorePackageBean != null, "score package should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(scorePackageBean.getId() != null, "score package id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        com.luxoft.scoremanager.server.model.entity.ScorePackage scorePackage = scorePackageDao.findOne(scorePackageBean.getId());
        scorePackage.setStage(scorePackageBean.getStage());
        scorePackageDao.saveAndFlush(scorePackage);
        if (scorePackageBean.getComponents().size() > 1) {
            this.updateComponentListInScorePackageByPackageId(scorePackageBean.getId(), scorePackageBean.getComponents());
        } else if (scorePackageBean.getComponents().size() == 1) {
            this.updateComponentInScorePackageByPackageId(scorePackageBean.getId(), scorePackageBean.getComponents().get(0));
        }
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public ScorePackageBean getScorePackageById(Integer id) {
        checkArgument(id != null, "id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        com.luxoft.scoremanager.server.model.entity.ScorePackage scorePackage = scorePackageDao.findOne(id);
        List<com.luxoft.scoremanager.server.model.entity.StaticData> staticDataList = staticDataDao.findAll();
        return new ScorePackageBean(scorePackage, staticDataList);
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<ComponentBean> getAllComponentByIdOfScorePackage(Integer id) {
        checkArgument(id != null, "id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        List<com.luxoft.scoremanager.server.model.entity.ComponentValue> componentValueList = componentValuesDao.getAllForPackage(id);
        List<ComponentBean> componentBeanList = new ArrayList<ComponentBean>();
        for (com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue : componentValueList) {
            componentBeanList.add(new ComponentBean(componentValue));
        }
        return componentBeanList;

    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<ComponentBean> getAllComponentByScorePackage(ScorePackageBean scorePackageBean) {
        checkArgument(scorePackageBean != null, "score package should be provided");
        //this is null checking method
        //noinspection ConstantConditions
        checkArgument(scorePackageBean.getId() != null, "score package id should be provided");
        //argument is checked
        //noinspection ConstantConditions
        List<com.luxoft.scoremanager.server.model.entity.ComponentValue> componentValueList = componentValuesDao.getAllForPackage(scorePackageBean.getId());
        List<ComponentBean> componentBeanList = new ArrayList<ComponentBean>();
        for (com.luxoft.scoremanager.server.model.entity.ComponentValue componentValue : componentValueList) {
            componentBeanList.add(new ComponentBean(componentValue));
        }
        return componentBeanList;
    }

    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    @Override
    public List<StaticDataBean> getAllStaticData() {
        List<com.luxoft.scoremanager.server.model.entity.StaticData> staticDataList = staticDataDao.findAll();
        List<StaticDataBean> staticDataBeanList = new ArrayList<StaticDataBean>();
        for (com.luxoft.scoremanager.server.model.entity.StaticData staticData : staticDataList) {
            staticDataBeanList.add(new StaticDataBean(staticData));
        }
        return staticDataBeanList;
    }
}
